package es.deusto.ingenieria.aike.puzzle;

import es.deusto.ingenieria.aike.formulation.Operator;
import es.deusto.ingenieria.aike.formulation.State;
import es.deusto.ingenieria.aike.puzzle.Car.Direction;

public class CarMovement extends Operator {

	public static enum Destination {
		STRAIGHT,
		RIGHT,
		LEFT;
	}

	private Destination destination;
	
	public CarMovement(Destination destination) {
		super("Go '" + destination.toString() + "'");
		this.destination = destination;		
	}
	
	protected boolean isApplicable(State state) {
		Environment env = (Environment)state.getInformation();	
		Environment env2 = env.clone();
		Car car = env2.getCar().clone();
		Board board = new Board();
		board = env2.getBoard();
		Flag flag = new Flag();
		flag = env2.getFlag();
		boolean result = false;
		switch (this.destination) {
			case STRAIGHT:
			{
				if (board.getTile(car.getY(),car.getX()).getCross() != 'x')
				{  
					switch (car.getDirection())
					{
						case UP: {if (car.getY() > 1) 
									{
										if ( !flag.getWallSituation()[3] || (car.getY() == flag.getPosition()[0]+1 && car.getX() != flag.getPosition()[1]) 
												 || car.getY() != flag.getPosition()[0]+1)
													result = true;
									} break;}								
						case RIGHT: {if (car.getX() < board.getTam()[1]-2)
									{
										if (!flag.getWallSituation()[0] || (car.getX() == flag.getPosition()[1]-1 && car.getY() != flag.getPosition()[0]) 
												 || car.getX() != flag.getPosition()[1]-1)
													result = true;
									} break;}
						case DOWN: {if (car.getY() < board.getTam()[0]-2)
									{
										if (!flag.getWallSituation()[1] || (car.getY() == flag.getPosition()[0]-1 && car.getX() != flag.getPosition()[1]) 
												 || car.getY() != flag.getPosition()[0]-1)
													result = true;
									} break;}
						case LEFT: {if (car.getX() > 1)
									{
										if (!flag.getWallSituation()[2] || (car.getX() == flag.getPosition()[1]+1  && car.getY() != flag.getPosition()[0]) 
												|| car.getX() != flag.getPosition()[1]+1)
											 		result = true;
									}}
					}
				} } break;
			case RIGHT:
			{
				if (board.getTile(car.getY(), car.getX()).getCross() == 'x')
				{
					switch (car.getDirection())
					{
						case UP: {if (car.getX() < board.getTam()[1]-2)
						{
							if (!flag.getWallSituation()[0] || (car.getX() == flag.getPosition()[1]-1  && car.getY() != flag.getPosition()[0]) 
									 || car.getX() != flag.getPosition()[1]-1)
										result = true;
						} break;}
						case RIGHT: {if (car.getY() < board.getTam()[0]-2)
						{
							if (!flag.getWallSituation()[1] || (car.getY() == flag.getPosition()[0]-1  && car.getX() != flag.getPosition()[1]) 
									 || car.getY() != flag.getPosition()[0]-1)
										result = true;
						} break;}
						case DOWN: {if (car.getX() > 1){
							if (!flag.getWallSituation()[2] || (car.getX() == flag.getPosition()[1]+1  && car.getY() != flag.getPosition()[0]) 
									|| car.getX() != flag.getPosition()[1]+1)
								 		result = true;
						} break;}
						case LEFT: {if (car.getY() > 1) {
							if (!flag.getWallSituation()[3] || (car.getY() == flag.getPosition()[0]+1 && car.getX() != flag.getPosition()[1]) 
									 || car.getY() != flag.getPosition()[0]+1)
										result = true;
						}}
					}
				}} break;
			case LEFT:
			{
				if (board.getTile(car.getY(), car.getX()).getCross() == 'x')
				{
					switch (car.getDirection())
					{
						case UP: {if (car.getX() > 1) {
							if (!flag.getWallSituation()[2] || (car.getX() == flag.getPosition()[1]+1 && car.getY() != flag.getPosition()[0]) 
									|| car.getX() != flag.getPosition()[1]+1)
								 		result = true;
						} break;}
						case RIGHT: {if (car.getY() > 1) {
							if (!flag.getWallSituation()[3] || (car.getY() == flag.getPosition()[0]+1 && car.getX() != flag.getPosition()[1]) 
									 || car.getY() != flag.getPosition()[0]+1)
										result = true;
						} break;}
						case DOWN: {if (car.getX() < board.getTam()[1]-2)
						{
							if (!flag.getWallSituation()[0] || (car.getX() == flag.getPosition()[1]-1 && car.getY() != flag.getPosition()[0]) 
									 || car.getX() != flag.getPosition()[1]-1)
										result = true;
						} break;}
						case LEFT: {if (car.getY() < board.getTam()[0]-2)
						{
							if (!flag.getWallSituation()[1] || (car.getY() == flag.getPosition()[0]-1 && car.getX() != flag.getPosition()[1]) 
									 || car.getY() != flag.getPosition()[0]-1)
										result = true;
						}}
					}
				}
			}
		}
		return result;
	}

	protected State effect(State state) {
		
		Environment env = (Environment)state.getInformation();	
		Environment env2 = env.clone();
		Car car = env2.getCar().clone();
		switch (this.destination) {
			case STRAIGHT:
				{switch (car.getDirection())
				{
					case UP: {car.setY(car.getY()-1); break;}
					case RIGHT: {car.setX(car.getX()+1); break;}
					case DOWN: {car.setY(car.getY()+1); break;}
					case LEFT: {car.setX(car.getX()-1);}
				} break;}
			case RIGHT:
				{switch (car.getDirection())
				{
					case UP: {car.setX(car.getX()+1);
							  car.setDirection(Direction.RIGHT); break;}
					case RIGHT: {car.setY(car.getY()+1);
								 car.setDirection(Direction.DOWN); break;}
					case DOWN: {car.setX(car.getX()-1);
								car.setDirection(Direction.LEFT); break;}
					case LEFT: {car.setY(car.getY()-1);
								car.setDirection(Direction.UP);}
				} break;}
			case LEFT:
				{switch (car.getDirection())
				{
					case UP: {car.setX(car.getX()-1);
								car.setDirection(Direction.LEFT); break;}
					case RIGHT: {car.setY(car.getY()-1);
					 			car.setDirection(Direction.UP); break;}
					case DOWN: {car.setX(car.getX()+1);
								car.setDirection(Direction.RIGHT); break;}
					case LEFT: {car.setY(car.getY()+1);
								car.setDirection(Direction.DOWN);}
				}}
		}
		env2.setCar(car);
		return new State(env2);
	}
}